【算法】动态规划+“背包九讲”原理超详细讲解+常见dp问题(9种)总结

您所在的位置:网站首页 dp 计算机 【算法】动态规划+“背包九讲”原理超详细讲解+常见dp问题(9种)总结

【算法】动态规划+“背包九讲”原理超详细讲解+常见dp问题(9种)总结

2024-05-26 18:43| 来源: 网络整理| 查看: 265

目录 一.动态规划(DP) 二.背包九讲 (1)完全背包 P1616 疯狂的采药(完全背包) (2)01背包 滚动数组 一维数组 P1048 采药(01背包) (3)多重背包 整数拆分(二进制拆分) P1776 宝物筛选(多重背包) (4)二维费用背包 P1507 NASA的食物计划(二维费用背包) (5)混合背包 P1833樱花(混合背包) (6)分组背包 P1757 通天之分组背包(分组背包) (7)树形背包 1.dfs 序 2.利用 dfs 序解决树形背包 P2014 选课(树形背包) (8)方案数问题凡是求方案数的问题一定都需要初始化(dp[0]=1) 1.P1164 小 A 点菜 2.P1466 集合 二. DP简单应用 三.LCS最长公共子序列 四.棋盘型高维(三维)动态规划 五.区间DP 六.前缀DP 七.树形DP 八.状压DP 九.斜率优化DP 十.概率DP/期望DP 一.动态规划(DP)

动态规划(DP)通俗讲解 1、什么是动态规划? 这里参考百度百科,动态规划是求解决策过程最优化的数学方法。把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。

2、什么时候要用动态规划? 如果要求一个问题的最优解(通常是最大值或者最小值),而且该问题能够分解成若干个子问题,并且小问题之间也存在重叠的子问题,则考虑采用动态规划。

3、怎么使用动态规划? 我把下面称为动态规划五部曲:

判题题意是否为找出一个问题的最优解 从上往下分析问题,大问题可以分解为子问题,子问题中还有更小的子问题 从下往上分析问题 ,找出这些问题之间的关联(状态转移方程) 讨论底层的边界问题 解决问题(通常使用数组进行迭代求出最优解) 文字来源

下面这个图是我们离散老师讲的一点动态规划,第一问是最基础的贪心,相信大家都会,第二问的DP如果是初学者建议把图片里的过程看一遍理解一下,(类似01背包)对理解下面的背包有好处。

二.背包九讲 (1)完全背包

考虑有 n 种物品,第 i 种物品的每个重量为 wi,价值为 vi,有无限多个。 我们手头有一个大小为 m的背包,需要算出能装下的最大总价值。

我们设 f(i) 表示大小为 i 的背包最多能装的价值,那么可以得到一个转移方程: f ( i ) = m a x f ( i − w   1   ) + v 1 , f ( i − w   2   ) + v 2 , . . . , f ( i − w   n   ) + v   n   f(i) = max{f(i − w~1~) + v1,f(i − w~2~) + v2,...,f(i − w~n~) + v~n~} f(i)=maxf(i−w 1 )+v1,f(i−w 2 )+v2,...,f(i−w n )+v n 写成简洁一些的形式: f ( i ) = m a x f ( i − w   j   ) + v   j   f(i) = max {f(i − w~j~) + v~j~} f(i)=maxf(i−w j )+v j 初始条件为: f ( 0 ) = 0 f(0) = 0 f(0)=0 尝试用代码来实现:

for (int i = 0; i vis[i]; for(int i=0;ic; for(int j=1;jw[i]>>c[i]; for(int i=1;i=v[i];--j) for(int k=mw;k>=w[i];--k) dp[j][k]=max(dp[j][k],dp[j-v[i]][k-w[i]]+c[i]); cout>c; if(!c)c=999999; for(int j=1;jvis[i]>>x; num=max(num,x); ++d[x]; dp[x][d[x]]=i; } for(int k=1;k=0;j--) for(int i=1;i=w[xx]) f[j]=max(f[j],f[j-w[xx]]+vis[xx]); } coutm; for(int i=1;i>a[i]; dp[0]=1; for(int i=1;i=a[i];j--) dp[j]+=dp[j-a[i]];// couts; for(int i=0;i=4)s1=s.substr(i-4,4); if(i>=6)s2=s.substr(i-6,6); if(i>=10)s3=s.substr(i-10,10); if(s1=="nico")dp[i]=max(dp[i],dp[i-4]+a); else dp[i]=max(dp[i],dp[i-1]); if(s2=="niconi")dp[i]=max(dp[i],dp[i-6]+b); else dp[i]=max(dp[i],dp[i-1]); if(s3=="niconiconi")dp[i]=max(dp[i],dp[i-10]+c); else dp[i]=max(dp[i],dp[i-1]); } cout=k成立) 断开前面,从当前位置往前 k−1项,和当前第 i 项,组成长度为 k 的序列。

时间复杂度O(N−K)

#include using namespace std; #define Pi acos(-1.0) typedef long long ll; const ll N=3e5+7; const ll mod=1e9+7; ll n,k,dp[N],a[N]; int main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>k; for(int i=1;i>a[i],dp[i]=mod; sort(a+1,a+1+n); dp[k]=a[k]-a[1]; for(int i=k+1;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3